package mission1;

import java.util.HashMap;


public class Operation {

	public String ChaineToPrint="";
	Node first=null;
	Node last=null;
	Node stack=null;
	HashMap<String, Double> ref=new HashMap<String, Double>();
	int stacksize=0;

	public Operation(String chaine){
		String[] A =chaine.split(" ");
		for(int i=0;i<A.length;i++){
			queue(A[i]);
		}
	}

	public String Launcher(){
		Analyse();
		return ChaineToPrint;
	}

	public String pop(){
		Node current=first;
		first=first.next;
		return current.action;
	}

	public void push(String A){
		Node node=new Node(A,first);
		first=node;
	}

	public void queue(String A){
		if(A.contains("\n")){
			String[] B=A.split("\n");
			A="";
			for(int i=0;i<B.length;i++){
				A=A+B[i];
			}
		}
		Node node=new Node(A,null);
		if(first==null){
			first=node;
			last=node;
		}
		else{
			last.next=node;
			last=node;
		}
	}

	
	public void Analyse(){
		PrintStack();
		PrintStack2();
		String A=pop();
		
		if(IsaDef(A)){
			push(""+getValueFromHashMap(A));
			Analyse();
		}
		
		if(A.startsWith("/")){
			String B=pop();
			pop();
			double db=value(B);
			A=A.substring(1);
			ref.put(A,new Double(db));
			Analyse();
		}
		
		if(IsaNumber(A)){
			String B="";
			try{
				B=pop();
			}catch(Exception e){
				
			}
			
			if(IsaDef(B)){
				push(""+getValueFromHashMap(B));
				push(A);
				Analyse();
			}
			if(B.matches("pop")){
				if (throwExeption()){

				}
				else{Analyse();}
			}
			if(B.matches("pstack")){
				push(A);
				ChaineToPrint=ChaineToPrint+A+"\n";
				System.out.println("*"+ChaineToPrint+"*");
				Analyse();
			}
			if((B.matches("add")||B.matches("sub")||B.matches("div")||B.matches("mul"))&&stacksize!=0){
				push(B);
				push(A);
				push(stack.action);
				stack=stack.next;
				stacksize--;
				Analyse();
			}
			if((B.matches("add")||B.matches("sub")||B.matches("div")||B.matches("mul"))&&stacksize==0){
				ChaineToPrint+=" Erreur ";
			}
			if(B.matches("dup")){
				push(A);
				push(A);
				Analyse();
			}
			if(IsaNumber(B)){
				String C=pop();
				if(IsaDef(C)){
					push(""+getValueFromHashMap(C));
					push(B);
					push(A);
					Analyse();
				}
				if(IsaNumber(C)){
					Node node=new Node(A,stack);
					stack=node;
					stacksize++;
					push(C);
					push(B);
					Analyse();
				}
				if(C.matches("pop")){
					push(A);
					Analyse();
				}
				if (C.matches("exch")){
					push(A);
					push(B);
					Analyse();
				}
				if(C.matches("add")){
					double da=value(A);
					double db=value(B);
					push(Double.toString(da+db));
					Analyse();
				}
				if(C.matches("sub")){
					double da=value(A);
					double db=value(B);
					push(Double.toString(da-db));
					Analyse();
				}
				if(C.matches("mul")){
					double da=value(A);
					double db=value(B);
					push(Double.toString(da*db));
					Analyse();
				}
				if(C.matches("div")){
					double da=value(A);
					double db=value(B);
					push(Double.toString(da/db));
					Analyse();

				}
				if(C.matches("eq")){
					double da=value(A);
					double db=value(B);
					push(Boolean.toString(da==db));
					Analyse();
				}
				if(C.matches("ne")){
					double da=value(A);
					double db=value(B);
					push(Boolean.toString(da!=db));
					Analyse();
				}
				if(C.matches("dup")){
					push(B);
					push(B);
					push(A);
					Analyse();
				}
				if(C.matches("def")){

				}
			}
		}
		if(A.matches("pop")){
			Analyse();
		}
		if(A.matches("true")){
			String B=pop();
			if(B.matches("pop")){
				if (throwExeption()){

				}
				else{Analyse();}
			}
			if(B.matches("pstack")){
				push(A);
				ChaineToPrint=ChaineToPrint+A+"\n";
				System.out.println("*"+ChaineToPrint+"*");
				Analyse();
			}
			if(B.matches("true")){
				String C=pop();
				if(C.matches("ne")){
					push("false");
				}
				if(C.matches("eq")){
					push("true");
				}
			}
			if(B.matches("false")){
				String C=pop();
				if(C.matches("ne")){
					push("true");
				}
				if(C.matches("eq")){
					push("false");
				}		
			}
		}

		if(A.matches("false")){
			String B=pop();
			if(B.matches("pop")){
				if (throwExeption()){

				}
				else{Analyse();}
			}
			if(B.matches("pstack")){
				push(A);
				ChaineToPrint=ChaineToPrint+A+"\n";
				System.out.println("*"+ChaineToPrint+"*");
				Analyse();
			}
			if(B.matches("true")){
				String C=pop();
				if(C.matches("ne")){
					push("true");
				}
				if(C.matches("eq")){
					push("false");
				}
			}
			if(B.matches("false")){
				String C=pop();
				if(C.matches("ne")){
					push("false");
				}
				if(C.matches("eq")){
					push("true");
				}			
			}
		}
		if(A.matches("pstack")){
			if (throwExeption()){
				
			}
			else{ChaineToPrint+="\n";
				Analyse();}
		}
		if((A.matches("add")||A.matches("sub")||A.matches("div")||A.matches("mul")||A.matches("ne")||A.matches("eq")) && stacksize==0){
			Analyse();
		}
		if((A.matches("add")||A.matches("sub")||A.matches("div")||A.matches("mul")||A.matches("ne")||A.matches("eq")) && stacksize!=0){
			push(A);
			push(stack.action);
			stack=stack.next;
			stacksize--;
			Analyse();
		}
	}


	private boolean IsaDef(String A) {
		 return (ref.containsKey(A));
	}
	private double getValueFromHashMap(String A){
		return (Double) ref.get(A);
	}

	private void PrintStack2() {
		Node current=stack;
		while(current!=null){
			System.out.println("**"+current.action+"**");
			current=current.next;
		}
		System.out.println("\n");
		
	}

	private boolean throwExeption() {
		try{
			String D= pop();
			push(D);
		}
		catch(Exception e){
			return true;
		}
		return false;
	}

	public boolean IsaNumber(String A){
		try{
			Double.valueOf(A);
		}
		catch(Exception e){
			return false;
		}
		return true;
	}

	public double value(String A){
		double d=0.0;
		try{
			d=Double.valueOf(A);
			d=Integer.valueOf(A);
		}
		catch(Exception e){
			System.out.println(e.getMessage());
		}
		return d;

	}

	public void PrintStack(){
		Node current=first;
		while(current!=null){
			System.out.println(current.action);
			current=current.next;
		}
		System.out.println("\n");
	}

}